package cn.web.tunnelrobot;

import cn.web.tunnelrobot.dao.ProjectDao;
import cn.web.tunnelrobot.dao.ThresholdDao;
import cn.web.tunnelrobot.dao.WarningRecordDao;
import cn.web.tunnelrobot.dto.*;
import cn.web.tunnelrobot.pojo.Threshold;
import cn.web.tunnelrobot.service.UserRecordService;
import cn.web.tunnelrobot.service.impl.RealTimeDataServiceImpl;
import cn.web.tunnelrobot.util.Constants;
import cn.web.tunnelrobot.websocket.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * 继承Application接口后项目启动时会按照执行顺序执行run方法
 * 通过设置Order的value来指定执行的顺序
 */
@Component
@Order(value = 1)
public class StartService implements ApplicationRunner {
    @Autowired
    private ThresholdDao thresholdDao;
    @Autowired
    private WarningRecordDao warningRecordDao;
    @Autowired
    private UserRecordService userRecordService;
    @Autowired
    private ProjectDao projectDao;
    @Autowired
    DataSource dataSource;

    //log4j
    Logger logger = LoggerFactory.getLogger(StartService.class);
    static Logger loggers = LoggerFactory.getLogger(StartService.class);
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    List<Warning> warningLists = new ArrayList<>();//报警信息
    //DigitalConversion temp = new DigitalConversion();//数字转文字==>语音播报
    public static ProjectDTO projectDTO = new ProjectDTO();//获取项目ID为1的项目信息=>语音播放(隧道米数)
    public static long midTime = 0;//时间戳
    public static Integer isBbool = 0;//true 开启，false 关闭

    @Override
    public void run(ApplicationArguments args) throws IOException, SQLException {

        Constants.TerminalControl = 0;
        //启动时给 阈值设置的ArrayList赋值
        Constants.list = thresholdDao.getThresholdList(null);
        for (Threshold threshold : Constants.list) {
            if (threshold.getThWarningSign() == 1) {
                Constants.temperature.add(threshold);
            } else if (threshold.getThWarningSign() == 2) {
                Constants.humidity.add(threshold);
            } else if (threshold.getThWarningSign() == 3) {
                Constants.oxygenConcentrations.add(threshold);
            } else if (threshold.getThWarningSign() == 4) {
                Constants.dustConcentration.add(threshold);
            } else if (threshold.getThWarningSign() == 5) {
                Constants.gasDensity.add(threshold);
            } else if (threshold.getThWarningSign() == 6) {
                Constants.batteryWarning.add(threshold);
            }else if(threshold.getThWarningSign() == 7){
                Constants.settle = threshold;
            } else if(threshold.getThWarningSign() == 8){
                Constants.convergence = threshold;
            }else if(threshold.getThWarningSign() == 9){
                Constants.cloudTurnAngle= threshold;
            }else if(threshold.getThWarningSign() == 10){
                Constants.spareBatteryWarning.add(threshold);
            }
        }
        //创建单线程池
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        //获取温度、湿度、氧气浓度、粉尘浓度、瓦斯浓度、光照强度、主电池电量、备用电池电量
        //并根据设置阀值判断是否要报警
        //此处功能分内外网，内网打开此功能，外网关闭此功能

            service.scheduleAtFixedRate(() -> hardwareInfo(), 4, 2, TimeUnit.SECONDS);
            //报警灯判断是否可以停止了
            service.scheduleAtFixedRate(() -> time1(), 5, 2, TimeUnit.SECONDS);
//            service.scheduleAtFixedRate(() ->obstacleInfo(), 4, 2, TimeUnit.SECONDS);

        //每日删除用户使用记录
        showDayTime();

        //监控页面获取  1：左视界面 2：上视界面 3：右视界面 4：俯视界面 5：机械臂 6：安全帽
        //直接在常量文件设置转流后的播放url,内网放内网播放url,外网放内网提供对外的播放url(待重写)
        //service.scheduleAtFixedRate(()->  getMonitoringAddress()  ,0, 6, TimeUnit.DAYS);

        //实时数据(首页)
        PushAlarm.myTimer();
        PushAlarmWarning.myTimer();//警告记录
        //实时语音webSocket
        VoiceTalkback.voiceIntercom();
        //获取ip
//        IpSocket.getip();

        //机器人实时位置
        service.scheduleAtFixedRate(() -> getRobotPosition(), 5, 5, TimeUnit.SECONDS);
        //充电状态实时获取(1小时执行一次，废弃了)
//        service.scheduleAtFixedRate(()-> getchargingsState(),0,1,TimeUnit.HOURS);
        //垃圾回收机制
        service.scheduleAtFixedRate(() ->  System.gc(), 2, 6, TimeUnit.HOURS);
        //查询隧道语音播报位置、项目简介
        projectDTO = projectDao.getDetailProjectById(1);

        //获取陀螺仪、超能检测、
        //安全帽信息检测（网络URL）,检测的服务来自于实验室的工控机
        //MyWebSocketClient.createClient();


        Server.start();//硬件采集数据(服务器中打开socket连接)
    }
    int max=100,min=0;
    int ran = (int) (Math.random()*(max-min)+min);
    /**
     * 实时获取机器人位置信息(二期,数据只用到了一个)
     * lbh
     */
    Integer speechCount = 0;//语音播报次数
    Integer speechDistance = 0;//语音播报距离
    private void getRobotPosition() {
        //获取机器人实时位置信息
        try {
            String distance = Constants.doGet(Constants.robotPosition);
            String value = distance.substring(2, 4);
            if(value.equals("OK")){
                System.out.println(value);
            }else{
                int i = Integer.parseInt(value);
                Constants.realTimeData.setRobotPosition(i);
            }
        } catch (Exception e) {
            logger.error("获取机器人实时位置信息报错");

        }
    }

    /**
     * 获取监控画面地址
     * 6天获取一次
     * 1：左视界面 2：上视界面 3：右视界面 4：俯视界面 5：机械臂 6：安全帽
     * 清晰度:高清:true 标清:false
     */
    private void getMonitoringAddress() {
        try {
            //开始执行耗时操作
            for (int i = 1; i < 7; i++) {
                if (i == 1) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 1);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                } else if (i == 2) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 2);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                } else if (i == 3) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 3);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                } else if (i == 4) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 4);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                        //logger.info("第四个监控画面:"+address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                } else if (i == 5) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 5);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                        //logger.info("机械臂:"+address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                }else if (i == 6) {
                    String address = Constants.doGet(Constants.monitorScreen + "?flag=" + 6);
                    if (address.substring(0, 4).equals("http")) {
                        Constants.getsRealMonitoringAddress.add(address);
                        //logger.info("安全帽:"+address);
                    } else {
                        Constants.getsRealMonitoringAddress.add("");
                    }
                }
            }
        } catch (Exception e) {
            logger.error("获取监控网址时发生异常");
//            e.printStackTrace();
        }
    }

    /**
     * 定时删除日志信息
     */
    private void showDayTime() {
        final ExecutorService exec = Executors.newFixedThreadPool(1);//创建线程
        Callable<String> call = new Callable<String>() {
            public String call(){
                //开始执行耗时操作
                Calendar calendar = Calendar.getInstance();
                int year = calendar.get(Calendar.YEAR);
                int month = calendar.get(Calendar.MONTH);
                int day = calendar.get(Calendar.DAY_OF_MONTH);
                calendar.set(year, month, day, 03, 00, 00);//设置要执行的日期时间
                Date defaultDate = calendar.getTime();
                Timer dTimer = new Timer();
                dTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        userRecordService.getUserRecordListYearAgo();
                        //logger.info("每日任务已经执行,时间" + format.format(new Date()));
                    }
                }, defaultDate, 24 * 60 * 60 * 1000);//24* 60* 60 * 1000
                return "线程执行完成.";
            }
        };
        try {
            Future<String> future = exec.submit(call);
            String obj = future.get(60, TimeUnit.SECONDS); //任务处理超时时间设为 60 秒
            logger.info("删除日志任务成功返回:" + obj);
        } catch (InterruptedException e) {
            //如果被中断
            logger.error("删除日志执行被中断");
//            e.printStackTrace();
        } catch (ExecutionException e) {
            // 如果执行异常
            logger.error("删除日志执行异常");
//            e.printStackTrace();
        } catch (TimeoutException t){
            //如果超时
            logger.error("删除日志请求超时!");
//            t.printStackTrace();
        }
        // 关闭线程池
        exec.shutdown();
    }
//private void obstacleInfo(){
//        try{
//            WarningRecordDTO warningRecordDTO = new WarningRecordDTO();
//            String obstacleResult = Constants.doGet(Constants.obstacle);
//            List<String> list = Arrays.asList(obstacleResult);
//            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
//            String info=list.get(0).substring(2,7);
//            if (info.equals("ERROR")&&Constants.obstacleStatus==1){
//                String value = Constants.doGet(Constants.carAlarmLight + "?bool=" + true);
//                warningRecordDTO.setWrDescribe("机器人遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
//                warningRecordDTO.setWrType(0);
//                warningRecordDao.addWarningRecordInfo(warningRecordDTO);
//                Warning warning = new Warning();
//                warning.setId(warningRecordDTO.getWrId());
//                warning.setCode(201);
//                warning.setMsg("机器人遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
//                warningLists.add(warning);
//            }
//        }catch (Exception e) {
//            logger.error("未连接机器人");
//        }
//}
    /**
     * 获取 PM2.5、电量、可燃气体、湿度、氧气、温度（二期）
     * @return
     * lbh
     */
    private void hardwareInfo(){
        try {
            warningLists = new ArrayList<>();
            //开始执行耗时操作
            Float humidity = 0.0f;    //湿度
            Float temperature = 0.0f; //温度
            Float oxygenConcentrations = 0.0f; //氧气
            Float gasDensity = 0.0f; //可燃气体
            Integer batteryWarning = 0;//电量
            Float dustConcentration = 0.0f;//PM2.5
            Integer spareBatteryWarning = 0; //底盘api获取得电量

            String result = Constants.doGet(Constants.hardwareAddress);
            if(StringUtils.isNotEmpty(result)) {
                result = result.substring(1, result.length() - 1);
                List<String> list1 = Arrays.asList(result.split(","));
                dustConcentration = Float.parseFloat(list1.get(0)); //PM2.5
                batteryWarning = Integer.parseInt(list1.get(1));   //电量
                gasDensity = Float.parseFloat(list1.get(2));//可燃气体
                humidity = Float.parseFloat(list1.get(3));//湿度
                oxygenConcentrations = Float.parseFloat(list1.get(4));//氧气
                temperature = Float.parseFloat(list1.get(5));//温度

                Constants.realTimeData.setDustConcentration(dustConcentration);
                Constants.realTimeData.setBatteryWarning(batteryWarning);
                Constants.realTimeData.setGasDensity(gasDensity);
                Constants.realTimeData.setHumidity(humidity);
                Constants.realTimeData.setOxygenConcentrations(oxygenConcentrations);
                Constants.realTimeData.setTemperature(temperature);
                //从机器段底盘api获取的系统状态中取电量信息
                String result2 = Constants.doGet(Constants.hardwareAddress2);
                if (!result2.contains("null")) {
                    JSONObject jsonObject = JSON.parseObject(result2);
                    JSONObject datalist = ((JSONObject) jsonObject.get("data"));
                    spareBatteryWarning= Integer.parseInt((datalist.get("battery").toString()));
                    Constants.realTimeData.setSpareBatteryWarning(spareBatteryWarning);
                    //历史数据增加Time字段
                    Constants.realTimeData.setTime(new Date());
                    RealTimeDataServiceImpl realTimeDataServiceimpl = new RealTimeDataServiceImpl();
                    realTimeDataServiceimpl.saveHitoryData(Constants.realTimeData);
                }else{
                    logger.error("底盘电池获取失败");
                }
            }
            /**
             * 获取机器端的遇到障碍物信息（除前避障）,将信息存储到 warningrecord表 和 常量 warningLists() (二期)
             * @return
             * lbh
             */
            WarningRecordDTO warningRecordDTO = new WarningRecordDTO();
            String obstacleResult = Constants.doGet(Constants.obstacle);
            List<String> list = Arrays.asList(obstacleResult);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
            if (list.get(0).equals("BError")){
                warningRecordDTO.setWrDescribe("机器人后方遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
                warningRecordDTO.setWrWarningTime(simpleDateFormat.parse(list.get(1)));
                warningRecordDTO.setWrType(0);
                warningRecordDao.addWarningRecordInfo(warningRecordDTO);
                Warning warning = new Warning();
                warning.setId(warningRecordDTO.getWrId());
                warning.setCode(201);
                warning.setMsg("机器人后方遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
                warningLists.add(warning);
            }else if (obstacleResult.equals("RLError")){
                warningRecordDTO.setWrDescribe("机器人两侧遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
                warningRecordDTO.setWrWarningTime(simpleDateFormat.parse(list.get(1)));
                warningRecordDTO.setWrType(0);
                warningRecordDao.addWarningRecordInfo(warningRecordDTO);
                Warning warning = new Warning();
                warning.setId(warningRecordDTO.getWrId());
                warning.setCode(202);
                warning.setMsg("机器人两侧遇到障碍，已紧急刹车，如需继续前进，请先按启动按钮！");
                warningLists.add(warning);
            }

            //判断从机器端获取的温度值是否在设置的阀值范围以内，是的话将数据存储到  warningrecord表 和 常量warningLists
            //同时打开请求机器端接口让机器人报警灯开启
            for (Threshold threshold1 : Constants.temperature) {
                if (temperature > threshold1.getThPrewarningLeftValue() && temperature <= threshold1.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold1.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold1.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(0);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(1);
                    warning.setLevel(threshold1.getThWarningLevel());
                    warning.setMsg(threshold1.getThWarningDescribe());
                    warningLists.add(warning);
                    //开启报警灯
                    timer();
                }
            }

            //湿度
            for (Threshold threshold2 : Constants.humidity) {
                if (humidity > threshold2.getThPrewarningLeftValue() && humidity <= threshold2.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold2.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold2.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(1);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(2);
                    warning.setLevel(threshold2.getThWarningLevel());
                    warning.setMsg(threshold2.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }

            //氧气浓度
            for (Threshold threshold3 : Constants.oxygenConcentrations) {
                if (oxygenConcentrations > threshold3.getThPrewarningLeftValue() && oxygenConcentrations <= threshold3.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold3.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold3.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(1);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(3);
                    warning.setLevel(threshold3.getThWarningLevel());
                    warning.setMsg(threshold3.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }

            //粉尘浓度
            for (Threshold threshold5 : Constants.dustConcentration) {
                if (dustConcentration > threshold5.getThPrewarningLeftValue() && dustConcentration <= threshold5.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold5.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold5.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(1);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(5);
                    warning.setLevel(threshold5.getThWarningLevel());
                    warning.setMsg(threshold5.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }

            //瓦斯浓度
            for (Threshold threshold6 : Constants.gasDensity) {
                if (gasDensity > threshold6.getThPrewarningLeftValue() && gasDensity <= threshold6.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold6.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold6.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(1);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(6);
                    warning.setLevel(threshold6.getThWarningLevel());
                    warning.setMsg(threshold6.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }

            //主电量预警
            for (Threshold threshold7 : Constants.batteryWarning) {
                if (batteryWarning > threshold7.getThPrewarningLeftValue() && batteryWarning <= threshold7.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold7.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold7.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(0);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(7);
                    warning.setLevel(threshold7.getThWarningLevel());
                    warning.setMsg(threshold7.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }
            //底盘获取电量判断
            for (Threshold threshold12 : Constants.spareBatteryWarning) {
                if (spareBatteryWarning > threshold12.getThPrewarningLeftValue() && spareBatteryWarning <= threshold12.getThPrewarningRightValue()) {
                    warningRecordDTO.setWrLevel(threshold12.getThWarningLevel());
                    warningRecordDTO.setWrDescribe(threshold12.getThWarningDescribe());
                    warningRecordDTO.setWrWarningTime(new Date());
                    warningRecordDTO.setWrType(0);
                    warningRecordDao.addWarningRecordInfo(warningRecordDTO);

                    Warning warning = new Warning();
                    warning.setId(warningRecordDTO.getWrId());
                    warning.setCode(12);//备用电量
                    warning.setLevel(threshold12.getThWarningLevel());
                    warning.setMsg(threshold12.getThWarningDescribe());
                    warningLists.add(warning);
                    timer();
                }
            }
        } catch (Exception e) {
            System.out.println(e);
            logger.error("未连接机器人");
        }
        Constants.warningList = warningLists;
    }


    /**
     * 定时开启/关闭警报灯
     */
    public static void timer() {
        Date date = new Date();
        midTime = date.getTime();
        isBbool = 1;
        String values = Constants.doGet(Constants.headlights + "?flag=1&bool=true");
        if (values.equals("success")) {
            loggers.info("报警灯控制开启!");
        }
    }
    /**
     * 方式三： 使用java.util.Timer类进行倒计时
     */
    public static void time1() {
        Date date1 = new Date();
        if (isBbool == 1){
            Date date = new Date();
            long midTime1 = date.getTime();
            if (midTime1 - midTime >= 60 * 1000){
                String value = Constants.doGet(Constants.headlights + "?flag=1&bool=false");
                if (value.equals("success")) {
                    isBbool = 0;
                    loggers.info("报警灯控制关闭!");
                }
            }
        }
    }

}
